﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using WfhTrader.Core.Quote;

namespace WfhTrader.Core.Trading
{
    /// <summary>
    /// 持仓类
    /// </summary>
    public class Position
    {
        /// <summary>
        /// 策略名称
        /// </summary>
        public string Strategy { get; private set; }

        /// <summary>
        /// 账户
        /// </summary>
        public Account Account { get; private set; }

        /// <summary>
        /// 证券
        /// </summary>
        public Security Security { get; private set; }

        /// <summary>
        /// 交易级别单位
        /// </summary>
        public BarUnit BarUnit { get; private set; }

        /// <summary>
        /// 仓位方向
        /// </summary>
        public DirectionType DirectionType { get; private set; }

        /// <summary>
        /// 持仓均价
        /// </summary>
        public double Price { get; private set; }

        /// <summary>
        /// 持仓总数
        /// </summary>
        public int Volume { get; private set; }


        /// <summary>
        /// 唯一键值
        /// </summary>
        private string key;

        /// <summary>
        /// 详细持仓
        /// </summary>
        private List<PositionDetail> positionDetails;



        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="strategy">策略名称</param>
        /// <param name="account">账户</param>
        /// <param name="security">证券</param>
        /// <param name="barUnit">交易级别单位</param>
        /// <param name="directionType">买卖方向</param>
        /// <param name="iTrade">交易接口</param>
        public Position(string strategy, Account account, Security security, BarUnit barUnit, DirectionType directionType)
        {
            this.Strategy       = strategy;
            this.Account        = account;
            this.Security       = security;
            this.BarUnit        = barUnit;
            this.DirectionType  = directionType;

            this.positionDetails = new List<PositionDetail>();
        }

        /// <summary>
        /// 开仓
        /// </summary>
        /// <param name="price">价格</param>
        /// <param name="volume">数量</param>
        public void Open(double price, int volume)
        {
            //持仓明细，初始成交量为0，在成交回报中更新成交数量
            PositionDetail detail = new PositionDetail();
            detail.OpenTime         = DateTime.Now;
            detail.Price            = price;
            detail.OrderVolume      = volume;
            detail.RemainVolume     = 0;
            positionDetails.Add(detail);

            this.Account.Trade.Open(this, detail);
        }

        /// <summary>
        /// 平仓
        /// </summary>
        /// <param name="price">价格</param>
        /// <param name="volume">数量</param>
        public void Close(double price, int volume)
        {
            this.Account.Trade.Close(this, price, volume);
        }

        /// <summary>
        /// 更新开仓以后的持仓情况
        /// </summary>
        /// <param name="tradeTime">交易时间</param>
        /// <param name="price">成交价格</param>
        /// <param name="volume">成交数量</param>
        public void UpdateOpenPosition(PositionDetail detail, DateTime tradeTime, double price, int volume)
        {
            //计算总的持仓均价（结果采取四舍六入法，保留两位小数）
            this.Price = Math.Round((this.Price * this.Volume + price * volume) / (this.Volume + volume), 2);

            //计算总的持仓总数
            this.Volume += volume;

            //更新持仓明细成交情况
            detail.RemainVolume += volume;
        }

        /// <summary>
        /// 更新平仓以后的持仓情况
        /// </summary>
        /// <param name="tradeTime">交易时间</param>
        /// <param name="price">成交价格</param>
        /// <param name="volume">成交数量</param>
        public void UpdateClosePosition(DateTime tradeTime, double price, int volume)
        {
            //计算持仓均价（结果采取四舍六入法，保留两位小数）
            this.Price = Math.Round((this.Price * this.Volume - price * volume) / (this.Volume - volume), 2);

            //计算持仓总数
            this.Volume -= volume;

            int v = volume;
            PositionDetail t;

            //依次将最晚的持仓明细平仓
            while( v > 0)
            {
                t = null;

                foreach (PositionDetail detail in positionDetails)
                {
                    if (t == null || (t != null && t.RemainVolume > 0 && detail.OpenTime.CompareTo(t.OpenTime) > 0))
                        t = detail;
                }

                if (t != null)
                {
                    if (t.RemainVolume >= v)
                    {
                        t.RemainVolume -= v;
                        v = 0;
                    }
                    else
                    {
                        v -= t.RemainVolume;
                        t.RemainVolume = 0;
                    }
                }
            }
        }

        /// <summary>
        /// 取得唯一键值
        /// </summary>
        public string Key
        {
            get
            {
                if (key == null)
                {
                    System.Text.StringBuilder sb = new System.Text.StringBuilder();

                    sb.Append(this.Strategy).Append("_")
                      .Append(this.Account.Broker.Code).Append("_")
                      .Append(this.Account.AccountNumber).Append("_")
                      .Append(this.Security.Code).Append("_")
                      .Append(this.BarUnit.Level).Append("_")
                      .Append(this.BarUnit.TimeSpan).Append("_")
                      .Append(this.DirectionType);

                    key = sb.ToString();
                }

                return key;
            }
        }
    }
}
